/*
*********************************************************************
* CHwmDataTip
* Based on CToolTipCtrl, adds a few features making it easier to use
* with non-frame windows.
*********************************************************************
* Frank LaPiana, HighWaterMark Communication Systems
* Sept 1998 - Initial version. A good portion of making this work
* came from
* "Tiptoe Through the ToolTips With Our All-Encompassing
* ToolTip Programmer's Guide" by Roger Jack, from April 1998
* Microsoft Systems Journal, found in the VC6 online documentation.
*********************************************************************
* Using Data Tips
* ---------------
*
* (1) [Optional] Include a member variable in your application class,
* or define a stand-alone global instance of CHwmDataTipCollection.
* This class can be used to perform global control of data tips,
* for instance, activation/de-activation.
*
*   // global instance of all our data tips, so we can control
*   // them from one point.
*   CHwmDataTipCollection  m_DataTipCollection;
*
* (2) if (1), then in your application InitInstance set the current
* activation flag, and then call the collection's "Update". Do
* this after any automatic windows are created, so that their
* status can be controlled by the global CHwmDataTipCollection
* instance.
*
*  // **************************************************************
*  // data tips - by default, disabled
*  // **************************************************************
*  m_DataTipCollection.m_ActiveFlag = FALSE;
*  m_DataTipCollection.Update();
*
* (3) In your view, dialog, or other window, create a member variable
* of CHwmDataTip.
*
*   // enables tool tips for the edit boxes and other controls
*   CHwmDataTip    m_DataTip;
*   BOOL     OnToolTipNeedText ( UINT id, NMHDR * pTTTStruct, LRESULT * pResult );
*
* (4) In your child window, add the following statements to the
* OnInitialUpdate or OnInitDialog:
*
*  // create the data tip control - automatically activates according to the collection if specified
*  int iReturn = m_DataTip.Create (this, TTS_ALWAYSTIP, &pApp->m_DataTipCollection);
*  if (iReturn == 0)
*  {
*   // add each tip we want
*   m_DataTip.AddTip (_TEXT("The program version and compile date."), IDC_ABOUT_VERSION);
*   <repeat for control or area>
*   m_DataTip.AddTip (_TEXT("Immediately update the statistics display."), IDC_STAT_UPDATE);
*  }
*
* (5) You'll have to override PreTranslateMessage, OnMouseMove as below
* so that the data tips will work correctly.
*
*  // *********************************************************************
*  // * PreTranslateMessage
*  // * Pass any interesting events to the data tip so that it can be
*  // * take action if necessary.
*  // *********************************************************************
*  BOOL CAboutView::PreTranslateMessage(MSG* pMsg)
*  {
*   // TODO: Add your specialized code here and/or call the base class
*   if (::IsWindow(m_DataTip.m_hWnd) && pMsg->hwnd == m_hWnd)
*   {
*    switch(pMsg->message)
*    {
*     case WM_MOUSEMOVE:
*     case WM_LBUTTONDOWN:
*     case WM_LBUTTONUP:
*     case WM_RBUTTONDOWN:
*     case WM_MBUTTONDOWN:
*     case WM_RBUTTONUP:
*     case WM_MBUTTONUP:
*      // enable any current tips
*      m_DataTip.RelayEvent(pMsg);
*      break;
*    }
*   }
*   return CFormView::PreTranslateMessage(pMsg);
*  }
*  // *********************************************************************
*  // * OnMouseMove
*  // * Let the datatip know that the mouse has moved in case something
*  // * was displayed.
*  // *********************************************************************
*  void CAboutView::OnMouseMove(UINT nFlags, CPoint point)
*  {
*   m_DataTip.OnMouseMove();
*
*   CFormView::OnMouseMove(nFlags, point);
*  }
*
* (6) Add the function OnToolTipNeedText (also in #3 above). This function
* is controlled by "EnableToolTips" and is used as a callback by the
* ToolTip common control when it needs text for a tip.
*
*  // *********************************************************************
*  // * OnToolTipNeedText
*  // * Handle callback from CWnd that we (may) need tip text. We'll
*  // * pass it down to the data tip class to handle
*  // *********************************************************************
*  BOOL CAboutView::OnToolTipNeedText (UINT id, NMHDR * pTTTStruct, LRESULT * pResult)
*  {
*   BOOL bReturn = m_DataTip.OnToolTipNeedText (id, pTTTStruct, pResult);
*   return (bReturn);
*  }
*
* (7) [Optional] If you are using the CHwmDataTipCollection then you will
* probably want to add it to your menu system so it can be toggled on
* or off. Add the logic to your menu handler (often CMainFrame or
* application). Add the appropriate routing to the message map.
*
*  // *********************************************************************
*  // * OnViewDataTips
*  // * Toggle the data tips display
*  // *********************************************************************
*  void CHwmCidApp::OnViewDataTips()
*  {
*   TRYSTART;
*    if (m_DataTipCollection.m_ActiveFlag)
*     m_DataTipCollection.m_ActiveFlag = FALSE;
*    else
*     m_DataTipCollection.m_ActiveFlag = TRUE;
*    m_DataTipCollection.Update();
*   TRYTERM;
*  }
*  // *********************************************************************
*  // * OnUpdateDataTips
*  // * Check/un-check the data tips menu item
*  // *********************************************************************
*  void CHwmCidApp::OnUpdateDataTips (CCmdUI* pCmdUI)
*  {
*   TRYSTART;
*    pCmdUI->SetCheck (m_DataTipCollection.m_ActiveFlag);
*   TRYTERM;
*  }
*
*********************************************************************
*/
#include "stdafx.h"
#include "CHwmDataTip.h"

#define TRYSTART
#define TRYTERM

IMPLEMENT_DYNCREATE(CHwmDataTip, CToolTipCtrl)

/*
*********************************************************************
* construction
*********************************************************************
*/
CHwmDataTip::CHwmDataTip()
        : CToolTipCtrl()
{
    TRYSTART;
    if (this)
    {
        m_pParent = NULL;
        m_ActiveFlag = FALSE;
        m_DisplayFlag = FALSE;
        m_TipArray.RemoveAll();
        m_pCollection = NULL;
    }
    TRYTERM;
}
/*
*********************************************************************
* destruction
*********************************************************************
*/
CHwmDataTip::~CHwmDataTip()
{
    TRYSTART;
    if (this)
    {
        // if parent window is still active, shut down tips for it
        TRYSTART;
        if ((m_pParent != NULL) && (m_pParent != INVALID_HANDLE_VALUE))
        {
            if ((m_pParent->m_hWnd != NULL) && (m_pParent->m_hWnd != INVALID_HANDLE_VALUE))
            {
                m_pParent->EnableToolTips(FALSE);
            }
        }
        TRYTERM;

        // if we belong to a collection, de-register
        TRYSTART;
        if (m_pCollection != NULL)
            m_pCollection->Deregister(this);
        TRYTERM;
        m_pCollection = NULL;

        m_pParent = NULL;
        m_ActiveFlag = FALSE;
        m_DisplayFlag = FALSE;

        CHwmDataTipInfo *  pTip;
        int      iLoop;
        int      iCount = GetCount();
        for (iLoop = 0; iLoop < iCount; iLoop++)
        {
            pTip = m_TipArray.GetAt(iLoop);
            TRYSTART;
            delete pTip;
            TRYTERM;
        }
        m_TipArray.RemoveAll();
    }
    TRYTERM;
}
/*
*********************************************************************
* Create
* Call this member before any other use of the tip control. The
* control must have the parent window so that it can calculate
* positions and other necessary information.
*
* Parameters
* ----------
* pParentWnd - parent window
*
* Returns
* -------
* ZERO on success, non-zero on error or failure.
*********************************************************************
*/
int CHwmDataTip::Create(CWnd *pParentWnd, DWORD dStyle /* = 0 */, CHwmDataTipCollection* pTipCollection /* = NULL */)
{
    TRYSTART;
    if (!this)
        return (1);

    if (pParentWnd == NULL)
        return (2);

    m_pParent = pParentWnd;

    // call the base function
    BOOL bReturn = CToolTipCtrl::Create(pParentWnd, dStyle);
    if (bReturn)
    {
        // tell the base class that the entire parent client area is a tool tip area
        bReturn = AddTool(pParentWnd);
        // activate the tip control/window
        Activate(TRUE);

        // maximum tip width
//   SetMaxTipWidth (100);

        // time before tip disappears
        // SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX);
        SetDelayTime(TTDT_AUTOPOP, 30000);

        // initial appearance of tip - 200 msec
        // SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 200);
        SetDelayTime(TTDT_INITIAL, 500);

        // delay until next tip is shown
        // SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 200);
        SetDelayTime(TTDT_RESHOW, 500);

        // add to the collection if specified
        if (pTipCollection != NULL)
        {
            TRYSTART;
            pTipCollection->Register(this);
//     m_pCollection = pTipCollection;
            TRYTERM;
        }

        return (0);
    }
    return (3);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* Activate
* Activates or de-activates the data tips.
* Create should be called first.
*
* Parameters
* ----------
* bActivate - TRUE to activate, FALSE to de-activate
*
* Returns
* -------
* none
*********************************************************************
*/
void CHwmDataTip::Activate(BOOL bActivate /* = TRUE */)
{
    TRYSTART;
    if (!this)
        return;

    // set our internal flag
    m_ActiveFlag = bActivate;

    // call the base function for activation
    CToolTipCtrl::Activate(bActivate);

    // set the parent's processing
    if ((m_pParent!= NULL) && (m_pParent != INVALID_HANDLE_VALUE))
    {
        if ((m_pParent->m_hWnd!= NULL) && (m_pParent->m_hWnd != INVALID_HANDLE_VALUE))
        {
            m_pParent->EnableToolTips(bActivate);
        }
    }
    return;
    TRYTERM;
    return;
}
/*
*********************************************************************
* AddTip
* Adds a new tip to the internal list of control areas.
*
* Parameters
* ----------
* pText - test to be displayed when mouse is over control area
* iResource - resource ID of the control on the parent
*  window which will use the tip.
* iNumber - programmer assigned ID number of the tip
*
* Returns
* -------
* ZERO on success, non-zero on failure or error
*********************************************************************
*/
int CHwmDataTip::AddTip(LPCTSTR pText, int iResource /* = 0 */, int iNumber /* = 0 */)
{
    CHwmDataTipInfo*  pTipInfo = NULL;

    TRYSTART;
    if (!this)
        return (100);
    if ((pText == NULL) || (pText == (LPCTSTR) INVALID_HANDLE_VALUE))
        return (101);
    if (m_pParent == NULL)
        return (102);


    // create new tip on the stack and fill it in
    pTipInfo = new CHwmDataTipInfo;
    if (pTipInfo == NULL)
        return (103);

    pTipInfo->StoreText(pText);
    pTipInfo->m_iResource = iResource;
    pTipInfo->m_ID = iNumber;

    if (iResource > 0)
    {
        CWnd *   pChild;

        // get the window for the resource id
        pChild = m_pParent->GetDlgItem(iResource);
        if (pChild == NULL)
            return (200);

        // get the screen coordinates of the control-child
        pChild->GetWindowRect(pTipInfo->m_TipArea);
        if (pTipInfo->m_TipArea.IsRectEmpty())
            return (201);

        // get the position within the client area of the parent
        m_pParent->ScreenToClient(pTipInfo->m_TipArea);
    }

    m_TipArray.Add(pTipInfo);
    return (0);
    TRYTERM;

    if (pTipInfo)
        delete pTipInfo;

    return (9999);
}
/*
*********************************************************************
* AddTip
* Adds a new tip to the internal list of control areas.
*
* Parameters
* ----------
* pControl - existing child window which will be the tip area
* iResource - resource ID of the control on the parent
*  window which will use the tip.
* iNumber - programmer assigned ID number of the tip
*
* Returns
* -------
* ZERO on success, non-zero on failure or error
*********************************************************************
*/
int CHwmDataTip::AddTip(LPCTSTR pText, CWnd *pControl, int iNumber)
{
    CHwmDataTipInfo*  pTipInfo = NULL;

    TRYSTART;
    if (!this)
        return (100);
    if ((pText == NULL) || (pText == (LPCTSTR) INVALID_HANDLE_VALUE))
        return (101);
    if (m_pParent == NULL)
        return (102);
    if ((pControl == NULL) || (pControl == INVALID_HANDLE_VALUE))
        return (103);

    // create new tip on the stack and fill it in
    pTipInfo = new CHwmDataTipInfo;
    if (pTipInfo == NULL)
        return (104);

    pTipInfo->StoreText(pText);
    pTipInfo->m_iResource = GetDlgCtrlID();
    pTipInfo->m_ID = iNumber;

    // get the screen coordinates of the control-child
    pControl->GetWindowRect(pTipInfo->m_TipArea);
    if (pTipInfo->m_TipArea.IsRectEmpty())
    {
        delete pTipInfo;
        return (201);
    }

    // calculate the offset between the two to get the
    // position within the client area of the parent
    m_pParent->ScreenToClient(pTipInfo->m_TipArea);

    m_TipArray.Add(pTipInfo);
    return (0);
    TRYTERM;

    if (pTipInfo)
        delete pTipInfo;

    return (9999);
}
/*
*********************************************************************
* AddTip
* Adds a new tip to the internal list of control areas.
*
* Parameters
* ----------
* iString - ID of resource string that will be used as a tip
* iResource - resource ID of the control on the parent
*  window which will use the tip.
* iNumber - programmer assigned ID number of the tip
*
* Returns
* -------
* ZERO on success, non-zero on failure or error
*********************************************************************
*/
int CHwmDataTip::AddTip(int iString, int iResource /* = 0 */, int iNumber /* = 0 */)
{
    CHwmDataTipInfo*  pTipInfo = NULL;
    CString     strLoad;

    TRYSTART;
    if (!this)
        return (100);
    if (iString < 1)
        return (101);
    if (m_pParent == NULL)
        return (102);

    // create new tip on the stack and fill it in

    int iTemp1 = strLoad.LoadString(iString);
    if (iTemp1 == 0)
        return (103); // the resource wasn't found

    pTipInfo = new CHwmDataTipInfo;
    if (pTipInfo == NULL)
        return (104);

    pTipInfo->StoreText(strLoad);
    pTipInfo->m_iResource = iResource;
    pTipInfo->m_ID = iNumber;

    if (iResource > 0)
    {
        CWnd *   pChild;

        // get the window for the resource id
        pChild = m_pParent->GetDlgItem(iResource);
        if (pChild == NULL)
        {
            delete pTipInfo;
            return (200);
        }

        // get the screen coordinates of the control-child
        pChild->GetWindowRect(pTipInfo->m_TipArea);
        if (pTipInfo->m_TipArea.IsRectEmpty())
        {
            delete pTipInfo;
            return (201);
        }

        // calculate the offset between the two to get the
        // position within the client area of the parent
        m_pParent->ScreenToClient(pTipInfo->m_TipArea);
    }

    m_TipArray.Add(pTipInfo);
    return (0);
    TRYTERM;

    if (pTipInfo)
        delete pTipInfo;

    return (9999);
}
/*
*********************************************************************
* AddTip
* Adds a new tip to the internal list of control areas.
*
* Parameters
* ----------
* iString - ID of resource string that will be used as a tip
* pControl - existing child window which will use the tip
* iNumber - programmer assigned ID number of the tip
*
* Returns
* -------
* ZERO on success, non-zero on failure or error
*********************************************************************
*/
int CHwmDataTip::AddTip(int iString, CWnd *pControl, int iNumber /* = 0 */)
{
    CHwmDataTipInfo*   pTipInfo = NULL;
    CString      strLoad;

    TRYSTART;
    if (!this)
        return (100);
    if (iString < 1)
        return (101);
    if (m_pParent == NULL)
        return (102);
    if ((pControl == NULL) || (pControl == INVALID_HANDLE_VALUE))
        return (103);

    // create new tip on the stack and fill it in
    int iTemp1 = strLoad.LoadString(iString);
    if (iTemp1 == 0)
        return (104); // the resource wasn't found

    pTipInfo = new CHwmDataTipInfo;
    if (pTipInfo == NULL)
        return (105);

    pTipInfo->StoreText(strLoad);
    pTipInfo->m_iResource = m_pParent->GetDlgCtrlID();
    pTipInfo->m_ID = iNumber;

    // get the screen coordinates of the control-child
    pControl->GetWindowRect(pTipInfo->m_TipArea);
    if (pTipInfo->m_TipArea.IsRectEmpty())
    {
        delete pTipInfo;
        return (201);
    }

    // calculate the offset between the two to get the
    // position within the client area of the parent
    m_pParent->ScreenToClient(pTipInfo->m_TipArea);

    m_TipArray.Add(pTipInfo);
    return (0);
    TRYTERM;

    if (pTipInfo)
        delete pTipInfo;

    return (9999);
}
/*
*********************************************************************
* GetCount
* Returns the number of tips we have information about
*
* Parameters
* ----------
* none
*
* Returns
* -------
* COUNT of tips, or 0 if none
*********************************************************************
*/
int CHwmDataTip::GetCount(void)
{
    TRYSTART;
    if (!this)
        return (0);

    int iTemp1 = m_TipArray.GetUpperBound() + 1;
    return (iTemp1);
    TRYTERM;
    return (0);
}
/*
*********************************************************************
* GetTipResource
* Returns the tip information for a given resource id
*
* Parameters
* ----------
* iResource - resource ID that we want to find
* TipInfo - returned tip information
*
* Returns
* -------
* a pointer on success,
* NULL on error or failure
*********************************************************************
*/
CHwmDataTipInfo * CHwmDataTip::GetTipResource(int iResource)
{
    CHwmDataTipInfo *pTip;

    TRYSTART;
    if (!this)
        return (NULL);

    int iCount = GetCount();
    int iLoop;

    for (iLoop = 0; iLoop < iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        if (pTip->m_iResource == iResource)
            return (pTip);
    }
    return (NULL);
    TRYTERM;
    return (NULL);
}
/*
*********************************************************************
* GetTipIndex
* Returns the tip information
*
* Parameters
* ----------
* iNumber - index number (0 to GetCount - 1) of the tip info wanted
* TipInfo - returned tip information
*
* Returns
* -------
* zero on success, non-zero on error or failure
*********************************************************************
*/
CHwmDataTipInfo * CHwmDataTip::GetTipIndex(int iNumber)
{
    CHwmDataTipInfo * pTip;

    TRYSTART;
    if (!this)
        return (NULL);

    int iCount = GetCount();
    if ((iNumber < 0) || (iNumber >= iCount))
        return (NULL);

    pTip = m_TipArray.GetAt(iNumber);
    return (pTip);
    TRYTERM;
    return (NULL);
}
/*
*********************************************************************
* GetTipID
* Returns the tip information for a given id
*
* Parameters
* ----------
* iNumber - ID that we want to find
* TipInfo - returned tip information
*
* Returns
* -------
* zero on success, non-zero on error or failure
*********************************************************************
*/
CHwmDataTipInfo * CHwmDataTip::GetTipID(int iNumber)
{
    CHwmDataTipInfo * pTip;

    TRYSTART;
    if (!this)
        return (NULL);

    int iCount = GetCount();
    int iLoop;

    for (iLoop = 0; iLoop < iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        if (pTip->m_ID == iNumber)
            return (pTip);
    }
    return (NULL);
    TRYTERM;
    return (NULL);
}
/*
*********************************************************************
* RemoveTipIndex
* Removes tip information
*
* Parameters
* ----------
* iNumber - index number (0 to GetCount - 1) of the tip info to
*  be removed
*
* Returns
* -------
* zero on success, non-zero on error or failure
*********************************************************************
*/
int CHwmDataTip::RemoveTipIndex(int iNumber)
{
    TRYSTART;
    if (!this)
        return (1);

    int iCount = GetCount();
    if ((iNumber < 0) || (iNumber >= iCount))
        return (2);

    CHwmDataTipInfo *pTipInfo = m_TipArray.GetAt(iNumber);
    m_TipArray.RemoveAt(iNumber);
    TRYSTART;
    delete pTipInfo;
    TRYTERM;
    return (0);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* RemoveTipResource
* Removes the tip information for a given resource id
*
* Parameters
* ----------
* iResource - resource ID that we want to find
*
* Returns
* -------
* zero on success, non-zero on error or failure
*********************************************************************
*/
int CHwmDataTip::RemoveTipResource(int iResource)
{
    CHwmDataTipInfo* pTip;

    TRYSTART;
    if (!this)
        return (1);

    int iCount = GetCount();
    int iLoop;

    for (iLoop = 0; iLoop < iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        if (pTip->m_iResource == iResource)
        {
            m_TipArray.RemoveAt(iLoop);
            TRYSTART;
            delete pTip;
            TRYTERM;
            return (0);
        }
    }
    return (2);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* RemoveTipID
* Removes the tip information for a given id
*
* Parameters
* ----------
* iNumber - ID that we want to find
*
* Returns
* -------
* zero on success, non-zero on error or failure
*********************************************************************
*/
int CHwmDataTip::RemoveTipID(int iNumber)
{
    CHwmDataTipInfo * pTipInfo;

    TRYSTART;
    if (!this)
        return (1);

    int iCount = GetCount();
    int iLoop;

    for (iLoop = 0; iLoop < iCount; iLoop++)
    {
        pTipInfo = m_TipArray.GetAt(iLoop);
        if (pTipInfo->m_ID == iNumber)
        {
            m_TipArray.RemoveAt(iLoop);
            TRYSTART;
            delete pTipInfo;
            TRYTERM;
            return (0);
        }
    }
    return (2);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* OnToolTipNeedText
* This must be relayed by the parent window (FormView, Dialog, etc);
* it tests for a "hit" on a tip area and then returns the text for
* it.
*
* Parameters
* ----------
* id - Identifier of the control that sent the notification.
*  Not used. The control id is taken from the NMHDR structure.
*
* pTTTStruct - A pointer to the NMTTDISPINFO structure.
*  This structure is also discussed further in The TOOLTIPTEXT Structure.
*
* pResult - A pointer to result code you can set before you return.
*  TTN_NEEDTEXT handlers can ignore the pResult parameter.
*
* Returns
* -------
* TRUE - text returned for a hit area,
* FALSE - no text associated
*********************************************************************
*/
BOOL CHwmDataTip::OnToolTipNeedText(UINT /* id */, NMHDR * pNMHDR, LRESULT * /* pResult */)
{
    TRYSTART;
    if (!this)
        return (FALSE);

    if (m_ActiveFlag != TRUE)
        return (FALSE);

    if ((m_pParent == NULL) || (m_pParent == INVALID_HANDLE_VALUE))
        return (FALSE);

    // recast the pointer to tool tip info
    TOOLTIPTEXT *pInfo = (TOOLTIPTEXT *) pNMHDR;

    // get the current cursor position
    CPoint CurPos;
    ::GetCursorPos(&CurPos);
    // convert point to client coordinates
    m_pParent->ScreenToClient(&CurPos);

    // if point isn't in client area, immediately return FALSE
    // - perhaps frame needs to handle it
    CRect ClientArea;
    m_pParent->GetClientRect(&ClientArea);
    if (ClientArea.PtInRect(CurPos) != TRUE)
        return (FALSE);

    // cycle through all of our tips and find the first one
    // that has this point inside it
    CHwmDataTipInfo *  pTipInfo;
    int      iLoop;
    int      iCount = GetCount();
    for (iLoop = 0; iLoop < iCount; iLoop++)
    {
        pTipInfo = m_TipArray.GetAt(iLoop);
        if (pTipInfo->m_TipArea.PtInRect(CurPos))
        {
            // return text for this tip
            pInfo->szText[0] = NULL;
            pInfo->lpszText = pTipInfo->m_pText;
            m_DisplayFlag = TRUE;
            m_DisplayTime = GetTickCount();
            return (TRUE);
        }
    }
    // clear out text to prevent erroneous messages
    pInfo->szText[0] = NULL;
    pInfo->lpszText = NULL;
    // always return true, we handled it somehow or other
    return (TRUE);
    TRYTERM;
    return (FALSE);
}
/*
*********************************************************************
* OnMouseMove
* The mouse has moved in the parent. If our flags say we have
* something displayed, close it.
*
* Parameters
* ----------
* none
*
* Returns
* -------
* none
*********************************************************************
*/
void CHwmDataTip::OnMouseMove(void)
{
    TRYSTART;
    if (!this)
        return;
    if (m_ActiveFlag != TRUE)
        return;
    if (m_DisplayFlag != TRUE)
        return;

    if ((GetTickCount() - m_DisplayTime) < 100)
        return;

    // send message to tell tool tip control to pop off the display
    Pop();
    m_DisplayFlag = FALSE;
    return;
    TRYTERM;
    return;
}





/*
#####################################################################
#####################################################################
# CHwmDataTipInfo
#####################################################################
#####################################################################
*/
// IMPLEMENT_DYNCREATE(CHwmDataTipInfo, CObject)

/*
*********************************************************************
* construction
*********************************************************************
*/
CHwmDataTipInfo::CHwmDataTipInfo()
// : CObject()
{
    m_ID = 0;
    m_iResource = 0;
    m_TipArea.SetRectEmpty();
    m_pText = NULL;
}
CHwmDataTipInfo::CHwmDataTipInfo(const CHwmDataTipInfo& CopyFrom)
// : CObject()
{
    TRYSTART;
    m_ID = CopyFrom.m_ID;
    m_iResource = CopyFrom.m_iResource;
    m_TipArea = CopyFrom.m_TipArea;
    m_pText = NULL;
    StoreText(CopyFrom.m_pText);
    TRYTERM;
}
/*
*********************************************************************
* destruction
*********************************************************************
*/
CHwmDataTipInfo::~CHwmDataTipInfo()
{
    TRYSTART;
    if (this)
    {
        m_ID = 0;
        m_iResource = 0;
        m_TipArea.SetRectEmpty();

        if (m_pText != NULL)
        {
            TRYSTART;
            free(m_pText);
            TRYTERM;
        }
        m_pText = NULL;
    }
    TRYTERM;
}
/*
*********************************************************************
* StoreText
* Stores the tip text as a fixed-length fixed-buffer string,
* to avoid overhead.
*********************************************************************
*/
void CHwmDataTipInfo::StoreText(LPCTSTR pSource)
{
    TRYSTART;
    if (!this)
        return;

    if (m_pText != NULL)
        free(m_pText);
    m_pText = NULL;

    if ((pSource == NULL) || (pSource == (LPCTSTR) INVALID_HANDLE_VALUE))
        return;

    int iLen = strlen(pSource);
    if (iLen == 0)
        return;

    m_pText = (LPSTR) malloc(iLen + 2);
    if (m_pText == NULL)
        return;
    strncpy(m_pText, pSource, iLen + 1);
    return;
    TRYTERM;
}





/*
#####################################################################
#####################################################################
# CHwmDataTipCollection
#####################################################################
#####################################################################
*/

/*
*********************************************************************
* construction
*********************************************************************
*/
CHwmDataTipCollection::CHwmDataTipCollection()
{
    m_ActiveFlag = FALSE;
}
/*
*********************************************************************
* destruction
*********************************************************************
*/
CHwmDataTipCollection::~CHwmDataTipCollection()
{
    TRYSTART;
    if (this)
    {
        int    iLoop;
        int    iCount = m_TipArray.GetUpperBound();
        CHwmDataTip* pTip;

        for (iLoop = 0; iLoop <= iCount; iLoop++)
        {
            pTip = m_TipArray.GetAt(iLoop);
            TRYSTART;
            if (pTip != NULL)
            {
                pTip->m_pCollection = NULL;
            }
            TRYTERM;
        }
        m_TipArray.RemoveAll();
    }
    TRYTERM;
}
/*
*********************************************************************
* Register
*********************************************************************
*/
int CHwmDataTipCollection::Register(CHwmDataTip * DataTipInfo)
{
    TRYSTART;
    if (!this)
        return (1);

    int    iLoop;
    int    iCount = m_TipArray.GetUpperBound();
    CHwmDataTip* pTip;

    for (iLoop = 0; iLoop <= iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        if (pTip == DataTipInfo)
            // already registered
            return (0);
    }
    // not found - remove it from any previous collection
    if (DataTipInfo->m_pCollection != NULL)
    {
        TRYSTART;
        DataTipInfo->m_pCollection->Deregister(DataTipInfo);
        TRYTERM;
    }
    // set it to point to this collection
    DataTipInfo->m_pCollection = this;
    // add it to the collection
    m_TipArray.Add(DataTipInfo);
    Update();
    return (0);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* Deregister
* Removes a datatip from the collection
*********************************************************************
*/
int CHwmDataTipCollection::Deregister(CHwmDataTip * DataTipInfo)
{
    TRYSTART;
    if (!this)
        return (1);

    int    iLoop;
    int    iCount = m_TipArray.GetUpperBound();
    CHwmDataTip* pTip;

    for (iLoop = 0; iLoop <= iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        if (pTip == DataTipInfo)
        {
            // registered - remove the data tip's pointer to the collection
            pTip->m_pCollection = NULL;
            // remove it from the collection as well
            m_TipArray.RemoveAt(iLoop);
            return (0);
        }
    }
    // not found
    return (2);
    TRYTERM;
    return (9999);
}
/*
*********************************************************************
* Update
* For each datatip in the collection, send it the current
* global control information.
*********************************************************************
*/
void CHwmDataTipCollection::Update(void)
{
    TRYSTART;
    if (!this)
        return;

    int    iLoop;
    int    iCount = m_TipArray.GetUpperBound();
    CHwmDataTip* pTip;

    for (iLoop = 0; iLoop <= iCount; iLoop++)
    {
        pTip = m_TipArray.GetAt(iLoop);
        TRYSTART;
        pTip->Activate(m_ActiveFlag);
        TRYTERM;
    }
    return;
    TRYTERM;
}

